package com.proxy.server.frontend;

import com.proxy.server.context.AppContext;
import com.proxy.server.frontend.adapter.FrontendCoreAdapter;
import com.proxy.server.frontend.adapter.FrontendPacketDecoder;
import com.proxy.server.frontend.adapter.FrontendPacketEncoder;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.util.concurrent.DefaultEventExecutorGroup;

import java.net.InetSocketAddress;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 前端代理服务器
 *
 * Created by liufish on 16/7/15.
 */
public class FrontendServer {

    private final ServerBootstrap serverBootstrap;
    private final EventLoopGroup eventLoopGroupBoss;
    private final EventLoopGroup eventLoopGroupWorker;
    private final DefaultEventExecutorGroup eventExecutorGroup;

    /**
     * 构造函数初始化netty线程boss1 loop3 group8 比较适合
     */
    public FrontendServer(){
        this.serverBootstrap = new ServerBootstrap();
        this.eventLoopGroupBoss = new NioEventLoopGroup(AppContext.getInstance().getFrontendProxy().getBoss(), new ThreadFactory() {
            private AtomicInteger index = new AtomicInteger(0);
            @Override
            public Thread newThread(Runnable r) {
                return new Thread(r,String.format("frontend_nio_boss_%s",index.decrementAndGet()));
            }
        });
        this.eventLoopGroupWorker = new NioEventLoopGroup(AppContext.getInstance().getFrontendProxy().getLoop(), new ThreadFactory() {
            private AtomicInteger index = new AtomicInteger(0);
            @Override
            public Thread newThread(Runnable r) {
                return new Thread(r,String.format("frontend_nio_worker_%s",index.decrementAndGet()));
            }
        });
        this.eventExecutorGroup = new DefaultEventExecutorGroup(AppContext.getInstance().getFrontendProxy().getEvent(), new ThreadFactory() {
            private AtomicInteger index = new AtomicInteger(0);
            @Override
            public Thread newThread(Runnable r) {
                return new Thread(r,String.format("frontend_nio_event_%s",index.decrementAndGet()));
            }
        });
    }


    /**
     * 启动netty代理
     */
    public void start() throws Exception{
        this.serverBootstrap
                .group(eventLoopGroupBoss,this.eventLoopGroupWorker)
                .channel(NioServerSocketChannel.class)
                .option(ChannelOption.SO_BACKLOG,1024)
                .option(ChannelOption.SO_REUSEADDR,true)
                .option(ChannelOption.SO_KEEPALIVE,true)
                .option(ChannelOption.SO_SNDBUF,65535)
                .option(ChannelOption.SO_RCVBUF,65535)
                .childOption(ChannelOption.TCP_NODELAY,true)
                .localAddress(AppContext.getInstance().getFrontendProxy().getPort());


        this.serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {

            @Override
            protected void initChannel(SocketChannel socketChannel) throws Exception {
                socketChannel.pipeline().addLast(eventExecutorGroup);
                socketChannel.pipeline().addLast(new FrontendPacketDecoder());
                socketChannel.pipeline().addLast(new FrontendPacketEncoder());
                socketChannel.pipeline().addLast(new FrontendCoreAdapter());
            }
        });

        ChannelFuture sync = this.serverBootstrap.bind().sync();
        sync.channel().localAddress();
        sync.channel().closeFuture().sync();
    }


    /**
     * 关闭前端连接
     */
    public void shutdown() {
        try {

            this.eventLoopGroupBoss.shutdownGracefully();

            this.eventLoopGroupWorker.shutdownGracefully();

            if (this.eventExecutorGroup != null) {
                this.eventExecutorGroup.shutdownGracefully();
            }
            System.exit(-1);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


}
